tagged_union.hppnamespace type_safe
{
template <typename T>
struct union_type;
template <typename ... Ts>
struct union_types;
template <typename ... Types>
class tagged_union;
template <typename ... Types, typename Func, typename ... Args>
void with(tagged_union<Types...>& u, Func&& f, Args&&... additional_args);
template <typename ... Types, typename Func, typename ... Args>
void with(const tagged_union<Types...>& u, Func&& f, Args&&... additional_args);
template <typename ... Types, typename Func, typename ... Args>
void with(tagged_union<Types...>&& u, Func&& f, Args&&... additional_args);
template <typename ... Types, typename Func, typename ... Args>
void with(const tagged_union<Types...>&& u, Func&& f, Args&&... additional_args);
template <typename ... Types>
void destroy(tagged_union<Types...>& u) noexcept;
template <typename ... Types>
void copy(tagged_union<Types...>& dest, const tagged_union<Types...>& org);
template <typename ... Types>
void move(tagged_union<Types...>& dest, tagged_union<Types...>&& org);
}
type_safe::union_type [variant]template <typename T>
struct union_type
{
constexpr union_type();
};
Tag type so no explicit template instantiation of function parameters is required.
type_safe::union_types [variant]template <typename ... Ts>
struct union_types
{
};
Very basic typelist.
type_safe::tagged_union [variant]template <typename ... Types>
class tagged_union
{
public:
using types = union_types<typename std::decay<Types>::type...>;
class type_id;
static constexpr type_id invalid_type = type_id();
tagged_union() noexcept = default;
~tagged_union() noexcept = default;
tagged_union(const tagged_union&) = delete;
tagged_union& operator=(const tagged_union&) = delete;
template <typename T, typename ... Args>
void emplace(union_type<T>, Args&&... args);
template <typename T>
void destroy(union_type<T> type) noexcept;
const type_id& type() const noexcept;
bool has_value() const noexcept;
template <typename T>
T& value(union_type<T> type) & noexcept;
template <typename T>
const T& value(union_type<T> type) const & noexcept;
template <typename T>
T&& value(union_type<T> type) && noexcept;
template <typename T>
const T&& value(union_type<T> type) const && noexcept;
};
A tagged union.
It is much like a plain old C union, but remembers which type it currently stores. It can either store one of the given types or no type at all.
Notes: Like the C union it does not automatically destroy the currently stored type, and copy operations are deleted.
type_safe::tagged_union::type_idclass type_id
: public strong_typedef<class type_safe::tagged_union::type_id, std::size_t>,
public strong_typedef_op::equality_comparison<type_id>,
public strong_typedef_op::relational_comparison<type_id>
{
public:
template <typename T>
static constexpr bool is_valid();
constexpr type_id() noexcept;
template <typename T>
constexpr type_id(union_type<T>) noexcept;
operator bool() const noexcept;
};
The id of a type.
It is a ts::strong_typedef for std::size_t and provides equality and relational comparison.
type_safe::tagged_union::type_id::is_validtemplate <typename T>
static constexpr bool is_valid();
Returns: true if T is a valid type, false otherwise.
type_safe::tagged_union::type_id::type_idconstexpr type_id() noexcept;
Effects: Initializes it to an invalid value.
Notes: The invalid value compares less than all valid values.
type_safe::tagged_union::type_id::type_idtemplate <typename T>
constexpr type_id(union_type<T>) noexcept;
Effects: Initializes it to the value of the type T. If T is not one of the types of the union types, it will be the same as the default constructor.
type_safe::tagged_union::type_id::operator booloperator bool() const noexcept;
Returns: true if the id is valid, false otherwise.
type_safe::tagged_union::invalid_typestatic constexpr type_id invalid_type = type_id();
A global invalid type id object.
type_safe::tagged_union::~tagged_union~tagged_union() noexcept = default;
Notes: Does not destroy the currently stored type.
type_safe::tagged_union::emplacetemplate <typename T, typename ... Args>
void emplace(union_type<T>, Args&&... args);
Effects: Creates a new object of given type by perfectly forwarding args.
Throws: Anything thrown by Ts constructor, in which case the union will stay empty.
Requires: The union must currently be empty. and T must be a valid type and constructible from the arguments.
type_safe::tagged_union::destroytemplate <typename T>
void destroy(union_type<T> type) noexcept;
Effects: Destroys the currently stored type by calling its destructor, and setting the union to the empty state.
Requires: The union must currently store an object of the given type.
type_safe::tagged_union::typeconst type_id& type() const noexcept;
Returns: The type_id of the type currently stored, or invalid_type if there is none.
type_safe::tagged_union::has_valuebool has_value() const noexcept;
Returns: true if there is a type stored, false otherwise.
type_safe::tagged_union::value(1) template <typename T>
T& value(union_type<T> type) & noexcept;
(2) template <typename T>
const T& value(union_type<T> type) const & noexcept;
(3) template <typename T>
T&& value(union_type<T> type) && noexcept;
(4) template <typename T>
const T&& value(union_type<T> type) const && noexcept;
Returns: A (const) lvalue/rvalue reference to the currently stored type.
Requires: The union must currently store an object of the given type.
type_safe::with [variant](1) template <typename ... Types, typename Func, typename ... Args>
void with(tagged_union<Types...>& u, Func&& f, Args&&... additional_args);
(2) template <typename ... Types, typename Func, typename ... Args>
void with(const tagged_union<Types...>& u, Func&& f, Args&&... additional_args);
(3) template <typename ... Types, typename Func, typename ... Args>
void with(tagged_union<Types...>&& u, Func&& f, Args&&... additional_args);
(4) template <typename ... Types, typename Func, typename ... Args>
void with(const tagged_union<Types...>&& u, Func&& f, Args&&... additional_args);
Effects: If the union is empty, does nothing. Otherwise let the union contain an object of type T. If the functor is callable for the T, calls its operator() passing it the stored object. Else does nothing.
type_safe::destroy [variant]template <typename ... Types>
void destroy(tagged_union<Types...>& u) noexcept;
Effects: Destroys the type currently stored in the ts::tagged_union, by calling u.destroy(union_type<T>{}).
type_safe::copy [variant](1) template <typename ... Types>
void copy(tagged_union<Types...>& dest, const tagged_union<Types...>& org);
(2) template <typename ... Types>
void move(tagged_union<Types...>& dest, tagged_union<Types...>&& org);
Effects: Copies the type currently stored in one ts::tagged_union to another. This is equivalent to calling dest.emplace(union_type<T>{}, org.value(union_type<T>{})) (1)
dest.emplace(union_type<T>{}, std::move(org).value(union_type<T>{})) (2), where T is the type currently stored in the union.
Throws: Anything by the copy/move constructor in which case nothing has changed.
Requires: dest must not store a type, and all types must be copyable/moveable.